package com.yzcrm.erp.crm.service;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.util.TypeUtils;
import com.jfinal.aop.Aop;
import com.jfinal.aop.Before;
import com.jfinal.aop.Inject;
import com.jfinal.kit.Kv;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.Model;
import com.jfinal.plugin.activerecord.Record;
import com.jfinal.plugin.activerecord.SqlPara;
import com.jfinal.plugin.activerecord.TableMapping;
import com.jfinal.plugin.activerecord.tx.Tx;
import com.yzcrm.common.config.paragetter.BasePageRequest;
import com.yzcrm.common.constant.BaseConstant;
import com.yzcrm.erp.admin.entity.AdminConfig;
import com.yzcrm.erp.admin.entity.AdminField;
import com.yzcrm.erp.admin.entity.AdminFieldv;
import com.yzcrm.erp.admin.entity.AdminRecord;
import com.yzcrm.erp.admin.entity.AdminScene;
import com.yzcrm.erp.admin.service.AdminFileService;
import com.yzcrm.erp.admin.service.AdminUserService;
import com.yzcrm.erp.crm.common.CrmEnum;
import com.yzcrm.erp.crm.entity.*;
import com.yzcrm.utils.BaseUtil;
import com.yzcrm.utils.ParamsUtil;
import com.yzcrm.utils.R;
import com.yzcrm.utils.TagUtil;

import java.util.*;
import java.util.stream.Collectors;

/**
 * crm模块操作记录
 *
 * @author hmb
 */
public class CrmRecordService<T extends Model>{

    @Inject
    private AdminFileService adminFileService;

    /**
     * 	属性kv
     */
    private static Map<String,Map<String,String>> propertiesMap = new HashMap<>();
    private static final String CRM_PROPERTIES_KEY = "crm:properties_map";

    private void init(){
        List<Record> recordList = Db.findByCache(CRM_PROPERTIES_KEY, CRM_PROPERTIES_KEY, Db.getSql("crm.record.getProperties"));
        Map<String,List<Record>> pMap = recordList.stream().collect(Collectors.groupingBy(record -> record.get("type")));
        pMap.forEach((k, v) -> {
            HashMap<String,String> resultMap = new HashMap<>();
            v.forEach(record -> resultMap.put(record.getStr("COLUMN_NAME"), record.getStr("COLUMN_COMMENT")));
            propertiesMap.put(k, resultMap);
        });
    }


    private static List<String> textList = new ArrayList<>();

    /**
     * 	更新记录
     *
     * @param oldObj  之前对象
     * @param newObj  新对象
     * @param crmEnum 类型
     */
    @SuppressWarnings("unchecked")
    public void updateRecord(T oldObj, T newObj, CrmEnum crmEnum){
        init();
        CrmActionRecord crmActionRecord = new CrmActionRecord();
        crmActionRecord.setCreateUserId(BaseUtil.getUser().getUserId());
        crmActionRecord.setCreateTime(new Date());
        searchChange(textList, oldObj._getAttrsEntrySet(), (newObj)._getAttrsEntrySet(), crmEnum.getType() + "");
        crmActionRecord.setTypes(crmEnum.getType() + "");
        crmActionRecord.setActionId(oldObj.getInt(TableMapping.me().getTable(oldObj.getClass()).getPrimaryKey()[0]));
        crmActionRecord.setContent(JSON.toJSONString(textList));
        if(textList.size() > 0){
            crmActionRecord.save();
        }
        textList.clear();
    }

    public void addRecord(Integer actionId, CrmEnum crmEnum){
        CrmActionRecord crmActionRecord = new CrmActionRecord();
        crmActionRecord.setCreateUserId(BaseUtil.getUser().getUserId());
        crmActionRecord.setCreateTime(new Date());
        crmActionRecord.setTypes(crmEnum.getType() + "");
        crmActionRecord.setActionId(actionId);
        ArrayList<String> strings = new ArrayList<>();
        strings.add("新建了" + crmEnum.getRemarks());
        crmActionRecord.setContent(JSON.toJSONString(strings));
        crmActionRecord.save();
    }

    public void updateRecord(JSONArray jsonArray, String batchId){
        if(jsonArray == null){
            return;
        }
        List<AdminFieldv> oldFieldList = new AdminFieldv().dao().find("select * from yzcrm_admin_fieldv where batch_id = ?", batchId);
        oldFieldList.forEach(oldField -> {
            jsonArray.forEach(json -> {
                AdminFieldv newField = TypeUtils.castToJavaBean(json, AdminFieldv.class);
                String oldFieldValue;
                String newFieldValue;
                if(oldField.getValue() == null){
                    oldFieldValue = "空";
                }else{
                    oldFieldValue = oldField.getValue();
                }
                if(newField.getValue() == null){
                    newFieldValue = "空";
                }else{
                    newFieldValue = newField.getValue();
                }
                if(oldField.getName() != null && oldField.getName().equals(newField.getName()) && ! oldFieldValue.equals(newFieldValue)){
                    textList.add("将" + oldField.getName() + " 由" + oldFieldValue + "修改为" + newFieldValue + "。");
                }
            });
        });
    }

    private void searchChange(List<String> textList, Set<Map.Entry<String,Object>> oldEntries, Set<Map.Entry<String,Object>> newEntries, String crmTypes){
        oldEntries.forEach(x -> {
            newEntries.forEach(y -> {
                Object oldValue = x.getValue();
                Object newValue = y.getValue();
                if(oldValue instanceof Date){
                    oldValue = DateUtil.formatDateTime((Date) oldValue);
                }
                if(newValue instanceof Date){
                    newValue = DateUtil.formatDateTime((Date) newValue);
                }
                if(oldValue == null || "".equals(oldValue)){
                    oldValue = "空";
                }
                if(newValue == null || "".equals(newValue)){
                    newValue = "空";
                }
                if(x.getKey().equals(y.getKey()) && ! oldValue.equals(newValue)){
                    if("owner_user_id".equals(x.getKey())){
                        newValue = Db.queryStr("select realname from `yzcrm_admin_user` where user_id = ?", newValue);
                        oldValue = Db.queryStr("select realname from `yzcrm_admin_user` where user_id = ?", oldValue);
                    }else if("customer_id".equals(x.getKey())){
                        newValue = Db.queryStr("select customer_name from `yzcrm_crm_customer` where customer_id = ?", newValue);
                        oldValue = Db.queryStr("select customer_name from `yzcrm_crm_customer` where customer_id = ?", oldValue);
                    }else if("business_id".equals(x.getKey())){
                        newValue = Db.queryStr("select business_name from `yzcrm_crm_business` where business_name = ?", newValue);
                        oldValue = Db.queryStr("select business_name from `yzcrm_crm_business` where business_name = ?", oldValue);
                    }else if("contract_id".equals(x.getKey())){
                        newValue = Db.queryStr("select name from `yzcrm_crm_contract` where contract_id = ?", newValue);
                        oldValue = Db.queryStr("select name from `yzcrm_crm_contract` where contract_id = ?", oldValue);
                    }else if("category_id".equals(x.getKey())){
                        newValue = Db.queryStr("select name from `yzcrm_crm_product_category` where category_id = ?", newValue);
                        oldValue = Db.queryStr("select name from `yzcrm_crm_product_category` where category_id = ?", oldValue);
                    }
                    if(! "update_time".equals(x.getKey()) && ! "create_user_id".equals(x.getKey())){
                        textList.add("将" + propertiesMap.get(crmTypes).get(x.getKey()) + " 由" + oldValue + "修改为" + newValue + "。");
                    }
                }
            });
        });
    }

    public R queryRecordList(String actionId, String crmTypes){
        List<Record> recordList = Db.find(Db.getSql("crm.record.queryRecordList"), actionId, crmTypes);
        recordList.forEach(record -> {
            List<String> list = JSON.parseArray(record.getStr("content"), String.class);
            record.set("content", list);
        });
        return R.ok().put("data", recordList);
    }

    /**
     * 	添加转移记录
     *
     * @param actionId
     */
    public void addConversionRecord(Integer actionId, CrmEnum crmEnum, Long userId){
        String name = Db.queryStr("select realname from yzcrm_admin_user where user_id = ?", userId);
        CrmActionRecord crmActionRecord = new CrmActionRecord();
        crmActionRecord.setCreateUserId(BaseUtil.getUser().getUserId());
        crmActionRecord.setCreateTime(new Date());
        crmActionRecord.setTypes(crmEnum.getType() + "");
        crmActionRecord.setActionId(actionId);
        ArrayList<String> strings = new ArrayList<>();
        strings.add("将" + crmEnum.getName() + "转移给：" + name);
        crmActionRecord.setContent(JSON.toJSONString(strings));
        crmActionRecord.save();
    }

    /**
     * 	同意售前新增记录
     *
     * @param actionId
     */
    public void addAcceptPreSalesRecord(Integer actionId, CrmEnum crmEnum, Long userId){
    	String name = Db.queryStr("select realname from yzcrm_admin_user where user_id = ?", userId);
        CrmActionRecord crmActionRecord = new CrmActionRecord();
        crmActionRecord.setCreateUserId(BaseUtil.getUser().getUserId());
        crmActionRecord.setCreateTime(new Date());
        crmActionRecord.setTypes(crmEnum.getType() + "");
        crmActionRecord.setActionId(actionId);
        ArrayList<String> strings = new ArrayList<>();
        strings.add(name + "接受了售前申请");
        crmActionRecord.setContent(JSON.toJSONString(strings));
        crmActionRecord.save();
    }
    
    /**
     * 	添加(锁定/解锁)记录
     */
    public void addIsLockRecord(String[] ids, String crmTypes, Integer isLock){
        CrmActionRecord crmActionRecord = new CrmActionRecord();
        crmActionRecord.setCreateUserId(BaseUtil.getUser().getUserId());
        crmActionRecord.setCreateTime(new Date());
        crmActionRecord.setTypes(crmTypes);
        ArrayList<String> strings = new ArrayList<>();
        if(isLock == 1){
            strings.add("将客户锁定。");
        }else{
            strings.add("将客户解锁。");
        }
        crmActionRecord.setContent(JSON.toJSONString(strings));
        for(String actionId : ids){
            crmActionRecord.setId(null);
            crmActionRecord.setActionId(Integer.valueOf(actionId));
            crmActionRecord.save();
        }
    }

    /**
     * 	潜在客户和目标客户之间的转化记录
     *
     * @param actionId
     * @param crmType
     */
    public void addConversionCustomerRecord(Integer actionId, Integer crmType, String name){
        CrmActionRecord crmActionRecord = new CrmActionRecord();
        crmActionRecord.setCreateUserId(BaseUtil.getUser().getUserId());
        crmActionRecord.setCreateTime(new Date());
        crmActionRecord.setTypes(crmType + "");
        crmActionRecord.setActionId(actionId);
        ArrayList<String> strings = new ArrayList<>();
        if(crmType == 1) {
        	strings.add("将目标客户\"" + name + "\"转化为潜在客户");
        }
        
        if(crmType == 2) {
        	strings.add("将潜在客户\"" + name + "\"转化为目标客户");
        }
        crmActionRecord.setContent(JSON.toJSONString(strings));
        crmActionRecord.save();
    }

    /**
     *	 放入公海
     *
     */
    public void addPutIntoTheOpenSeaRecord(Collection actionIds, String crmTypes, String content){
        CrmActionRecord crmActionRecord = new CrmActionRecord();
        if(BaseUtil.getUser() == null){
            crmActionRecord.setCreateUserId(BaseConstant.SUPER_ADMIN_USER_ID);
        }else{
            crmActionRecord.setCreateUserId(BaseUtil.getUser().getUserId());
        }
        crmActionRecord.setCreateTime(new Date());
        crmActionRecord.setTypes(crmTypes);
        ArrayList<String> strings = new ArrayList<>();
        strings.add("将客户放入公海" + " " + content);
        crmActionRecord.setContent(JSON.toJSONString(strings));
        for(Object actionId : actionIds){
            crmActionRecord.remove("id");
            crmActionRecord.setActionId((Integer) actionId);
            crmActionRecord.save();
        }
    }


    /**
     *	 添加分配客户记录
     *
     */
    public void addDistributionRecord(String actionId, String crmTypes, Long userId){
        for(String id : actionId.split(",")){
            if(StrUtil.isEmpty(id)){
                continue;
            }
            ArrayList<String> strings = new ArrayList<>();
            String name = Db.queryStr("select realname from yzcrm_admin_user where user_id = ?", userId);
            CrmActionRecord crmActionRecord = new CrmActionRecord();
            crmActionRecord.setCreateUserId(BaseUtil.getUser().getUserId());
            crmActionRecord.setCreateTime(new Date());
            crmActionRecord.setTypes(crmTypes);
            crmActionRecord.setActionId(Integer.valueOf(id));
            if(userId == null){
                //领取
                strings.add("领取了客户");
            }else{
                //管理员分配
                strings.add("将客户分配给：" + name);
            }
            crmActionRecord.setContent(JSON.toJSONString(strings));
            crmActionRecord.save();
        }
    }


    /**
     * @author wyq
     *	 删除跟进记录
     */
    public R deleteFollowRecord(Integer recordId){
        adminFileService.removeByBatchId(Db.queryStr("select batch_id from `yzcrm_admin_record` where record_id = ?",recordId));
        return AdminRecord.dao.deleteById(recordId) ? R.ok() : R.error();
    }

    /**
     * @author wyq
     * 	查询跟进记录类型
     */
    public R queryRecordOptions(){
        List<String> list = Db.query("select value from yzcrm_admin_config where name = 'followRecordOption'");
        return R.ok().put("data", list);
    }

    /**
     * @author wyq
     *	 设置跟进记录类型
     */
    @Before(Tx.class)
    public R setRecordOptions(List<String> list){
        Db.delete("delete from yzcrm_admin_config where name = 'followRecordOption'");
        for(int i = 0; i < list.size(); i++){
            AdminConfig adminConfig = new AdminConfig();
            adminConfig.setName("followRecordOption");
            adminConfig.setValue(list.get(i));
            adminConfig.setDescription("跟进记录选项");
            adminConfig.save();
        }
        return R.ok();
    }
    
    /**
     * @author wyq
     * 	查询跟进记录类型
     */
    public R queryRecordContentTemplate(){
    	List<String> list = Db.query("select value from yzcrm_admin_config where name = 'followRecordContentTemplate'");
        return R.ok().put("data", list);
    }

    /**
     * @author wyq
     * 	设置跟进记录类型
     */
    @Before(Tx.class)
    public R setRecordContentTemplate(String value){
        Db.delete("delete from yzcrm_admin_config where name = 'followRecordContentTemplate'");
        AdminConfig adminConfig = new AdminConfig();
        adminConfig.setName("followRecordContentTemplate");
        adminConfig.setValue(value);
        adminConfig.setDescription("跟进记录内容模版");
        adminConfig.save();
        return R.ok();
    }
    
    /**
     * @author lg
     * 	查询跟进记录列表
     */
    public R queryFollowRecords(BasePageRequest basePageRequest){
    	JSONObject jsonObject = basePageRequest.getJsonObject();
    	
    	Integer sceneId = jsonObject.getInteger("sceneId");
    	Integer type = jsonObject.getInteger("type");
    	
        JSONObject data = new JSONObject();
////     	功能模块
//        String realm; 
//        switch(type) {
//        case 2:
//        case 12:
//        	realm = "customer";
//        }
//    	处理查询条件中的场景
        if(sceneId != null && sceneId != 0){
            data = JSON.parseObject(AdminScene.dao.findById(sceneId).getData());
        }
        if(jsonObject.getJSONObject("data") != null){
            if(data != null){
                data.putAll(jsonObject.getJSONObject("data"));
            }
        }
        jsonObject.put("data",data);
        
//    	sql语句的配置容器
    	Kv kv = new Kv();
    	List<JSONObject> queryList = new ArrayList<>();
        
//    	查询参数处理成SQL语句
    	String search = jsonObject.getString("search");
        if(StrUtil.isNotEmpty(search)){
			if (!appendSqlSearch(queryList, search)){
				return R.error("参数包含非法字段");
			}
        }
        
//    	查询参数处理成SQL语句
        if (!appendSqlCondition(kv, queryList, jsonObject.getJSONObject("data"))){
            return R.error("参数包含非法字段");
        }

    	//	分页配置
    	if(StrUtil.isEmpty(jsonObject.getString("excel"))){
            kv.set("page", (basePageRequest.getPage() - 1) * basePageRequest.getLimit()).set("limit", basePageRequest.getLimit());
        }
    	
//    	根据登录用户的权限编写sql语句
    	StringBuilder conditions = new StringBuilder();
    	Long userId = BaseUtil.getUserId();
        List<Integer> roles = BaseUtil.getUser().getRoles();
        conditions.append(" and a.create_user_id is not null");
        if(!BaseConstant.SUPER_ADMIN_USER_ID.equals(userId) && !roles.contains(BaseConstant.SUPER_ADMIN_ROLE_ID)) {
        	//	非管理员
        	List<Long> longs = Aop.get(AdminUserService.class).queryUserByAuth(userId, "followRecord");
        	if(longs != null && longs.size() > 0){
        		conditions.append(" and (a.create_user_id in (").append(StrUtil.join(",", longs)).append(")");
        		conditions.append(")");
        	}
        }
        JSONObject sqlObject = new JSONObject();
        sqlObject.put("sql", conditions.toString());
        sqlObject.put("type", 1);
        queryList.add(sqlObject);
    	kv.set("queryList",queryList);
    	SqlPara sqlPara = Db.getSqlPara("crm.record.queryFollowRecords", kv);
    	List<Record> recordList = Db.find(sqlPara);
        recordList.forEach(record -> {
            adminFileService.queryByBatchId(record.getStr("batch_id"), record);
            String businessIds = record.getStr("business_ids");
            List<CrmBusiness> businessList = new ArrayList<>();
            if(businessIds != null){
                String[] businessIdsArr = businessIds.split(",");
                for(String businessId : businessIdsArr){
                    businessList.add(CrmBusiness.dao.findById(Integer.valueOf(businessId)));
                }
            }
            String contactsIds = record.getStr("contacts_ids");
            List<CrmContacts> contactsList = new ArrayList<>();
            if(contactsIds != null){
                String[] contactsIdsArr = contactsIds.split(",");
                for(String contactsId : contactsIdsArr){
                    contactsList.add(CrmContacts.dao.findById(Integer.valueOf(contactsId)));
                }
            }
            record.set("business_list", businessList).set("contacts_list", contactsList);
        });
        //总数
        SqlPara countSql = Db.getSqlPara("crm.record.queryFollowRecordCount", kv);
        Integer count = Db.queryInt(countSql.getSql(), countSql.getPara());
        return R.ok().put("data",kv.by("list", recordList).set("totalRow",count));
    }
    
    /**
     * @author lg
     * 	查询跟进记录详情
     */
    public R queryFollowRecordById(Integer recordId){
    	Record record = Db.findFirst(Db.getSql("crm.record.queryFollowRecordById"),recordId);
    	adminFileService.queryByBatchId(record.getStr("batch_id"), record);
        String businessIds = record.getStr("business_ids");
        List<CrmBusiness> businessList = new ArrayList<>();
        if(businessIds != null){
            String[] businessIdsArr = businessIds.split(",");
            for(String businessId : businessIdsArr){
                businessList.add(CrmBusiness.dao.findById(Integer.valueOf(businessId)));
            }
        }
        String contactsIds = record.getStr("contacts_ids");
        List<CrmContacts> contactsList = new ArrayList<>();
        if(contactsIds != null){
            String[] contactsIdsArr = contactsIds.split(",");
            for(String contactsId : contactsIdsArr){
                contactsList.add(CrmContacts.dao.findById(Integer.valueOf(contactsId)));
            }
        }
        record.set("business_list", businessList).set("contacts_list", contactsList);
        return R.ok().put("data",record);
    }
    
    /**
     * 	根据查询内容查询跟进记录列表
     */
    
    private boolean appendSqlSearch(List<JSONObject> queryList, String search) {
        if (!ParamsUtil.isValid(search)) {
            return false;
        }
        StringBuilder conditions = new StringBuilder();
        conditions.append(" and (customer_name like '%").append(search).append("%')");
        JSONObject sqlObject = new JSONObject();
        sqlObject.put("sql", conditions.toString());
        sqlObject.put("type", 2);
        queryList.add(sqlObject);
        return true;
    }
    
    /**
     * 	根据查询条件拼接sql语句
     */
    private boolean appendSqlCondition(Kv kv, List<JSONObject> queryList, JSONObject data) {
    	List<JSONObject> jsonObjectList = new ArrayList<>();
        if(data != null){
            data.forEach((k, v) -> jsonObjectList.add(JSON.parseObject(v.toString())));
        }
    	for(JSONObject jsonObject : jsonObjectList){
            String condition = jsonObject.getString("condition");
            String value = jsonObject.getString("value");
            String name = jsonObject.getString("name");
            StringBuilder conditions = new StringBuilder();
            JSONObject sqlObject = new JSONObject();
            if(! ParamsUtil.isValid(name)){
                return false;
            }
            if(StrUtil.isNotEmpty(value) && ! ParamsUtil.isValid(value)){
                return false;
            }
            if(StrUtil.isNotEmpty(jsonObject.getString("start")) && ! ParamsUtil.isValid(jsonObject.getString("start"))){
                return false;
            }
            if(StrUtil.isNotEmpty(jsonObject.getString("end")) && ! ParamsUtil.isValid(jsonObject.getString("end"))){
                return false;
            }
            String formType = jsonObject.getString("formType");
            if(StrUtil.isNotEmpty(value) || StrUtil.isNotEmpty(jsonObject.getString("start")) || StrUtil.isNotEmpty(jsonObject.getString("end"))){
            	sqlObject.put("name",name);
                conditions.append(" and ").append(name);
                if("is".equals(condition)){
                    conditions.append(" = '").append(value).append("'");
                    sqlObject.put("connector","=");
                    sqlObject.put("value","'"+value+"'");
                }else if("isNot".equals(condition)){
                    conditions.append(" != '").append(value).append("'");
                    sqlObject.put("connector","!=");
                    sqlObject.put("value","'"+value+"'");
                }else if("contains".equals(condition)){
                    conditions.append(" like '%").append(value).append("%'");
                    sqlObject.put("connector","like");
                    sqlObject.put("value","'%"+value+"%'");
                }else if("notContains".equals(condition)){
                    conditions.append(" not like '%").append(value).append("%'");
                    sqlObject.put("connector","not like");
                    sqlObject.put("value","'%"+value+"%'");
                }else if("isNull".equals(condition)){
                    conditions.append(" is null");
                    sqlObject.put("connector","is null");
                    sqlObject.put("value","");
                }else if("isNotNull".equals(condition)){
                    conditions.append(" is not null");
                    sqlObject.put("connector","is not null");
                    sqlObject.put("value","");
                }else if("gt".equals(condition)){
                    conditions.append(" > ").append(value);
                    sqlObject.put("connector",">");
                    sqlObject.put("value",value);
                }else if("egt".equals(condition)){
                    conditions.append(" >= ").append(value);
                    sqlObject.put("connector",">=");
                    sqlObject.put("value",value);
                }else if("lt".equals(condition)){
                    conditions.append(" < ").append(value);
                    sqlObject.put("connector","<");
                    sqlObject.put("value",value);
                }else if("elt".equals(condition)){
                    conditions.append(" <= ").append(value);
                    sqlObject.put("connector","<=");
                    sqlObject.put("value",value);
                }else if("in".equals(condition)){
                    conditions.append(" in (").append(value).append(")");
                    sqlObject.put("connector","in");
                    sqlObject.put("value","("+value+")");
                }
                if("datetime".equals(formType)){
                    conditions.append(" between '").append(jsonObject.getString("start")).append("' and '").append(jsonObject.getString("end")).append("'");
                    sqlObject.put("connector","between");
                    sqlObject.put("value","'"+jsonObject.getString("start")+"'"+" and '"+jsonObject.getString("end")+"'");
                }
                if("date".equals(formType)){
                    conditions.append(" between '").append(jsonObject.getString("startDate")).append("' and '").append(jsonObject.getString("endDate")).append("'");
                    sqlObject.put("connector","between");
                    sqlObject.put("value","'"+jsonObject.getString("startDate")+"'"+" and '"+jsonObject.getString("endDate")+"'");
                }
            }else {
            	continue;
            }
            String sql = conditions.toString();
            sql = sql.replace(name, "a."+name);
            sqlObject.put("type", 1);
            sqlObject.put("sql", sql);
            queryList.add(sqlObject);
    	}
    	return true;
    }
}
